﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using OxyPlot;
using OxyPlot.Axes;
using RunningWavelet.DataGenerators;
using RunningWavelet.Extensions;
using WaveletApplication;

namespace RunningWavelet.WaveletController
{
    public class RunningWaveletController
    {
        private readonly IUserFields _settings;
        private SignalBuffer _buffer; 
        private readonly WaveletSettings _activeWavelet;
        private RunningProcessor _rwp;
        private Thread t2;
        private int _activePlot = 1;

        public RunningWaveletController(IUserFields settings)
        {
            //Инициализация доступа к пользовательским полям и настройкам
            _settings = settings;
            settings.SetController(this);

            //Инициализация настроек генератора
            ReInitializeGenerator(_settings.GeneratorName);

            //Инициализация активного (выбранного пользователем) вейвлета
            _activeWavelet = _settings.WaveletSettings.ActiveWavelet;

            //Настройка буфера графика
            //_settings.Chart1Data = new FixedSizedQueue<DataPoint>() { Limit = _settings.WaveletSettings.PlotBufferLength };

            //Настройка буфера вейвлет преобразования
            _buffer =
                new SignalBuffer(
                    WaveletTools.GetWaveletPhase(_activeWavelet.H0.Length,
                        _settings.WaveletSettings.DecompilationDepth), _settings.WaveletSettings.DecompilationDepth);
            
            //Инициализация класса вейвлет обработки
            _rwp = new RunningProcessor(_buffer, _activeWavelet);
        }

        public GenerableBase Generator { set; get; }

        public void ReInitializeGenerator(string generatorName)
        {
            switch (generatorName)
            {
                case "Синус генератор":
                    Generator = new SinGenerator()
                    {
                        SignalAmplitude = 10,
                        SignalFrequency = 2,
                        NoiseAmplitude = 2
                    };
                    break;
                case "Подключение Wago":
                    Generator = new WagoGenerator
                    {
                        WagoAddressIp = _settings.ConnectionSettings.WagoAddressIp,
                        WagoPort = _settings.ConnectionSettings.WagoPort,
                        WagoTimeOut = _settings.ConnectionSettings.WagoTimeOut,
                        WagoRegisterStart = _settings.ConnectionSettings.WagoRegisterStart,
                        WagoRegisterCount = _settings.ConnectionSettings.WagoRegisterCount,
                        WagoPollCycle = _settings.ConnectionSettings.WagoPollCycle
                    };
                    break;
                case "Тестовые значения":
                    //throw new NotImplementedException("Обработка тестовых значений на текущий момент не поддерживается");
                    break;
            }
        }

        public void UpdateWaveletSettings()
        {
            _buffer =
                new SignalBuffer(
                    WaveletTools.GetWaveletPhase(_activeWavelet.H0.Length,
                        _settings.WaveletSettings.DecompilationDepth), _settings.WaveletSettings.DecompilationDepth);
            _rwp = new RunningProcessor(_buffer, _activeWavelet);
        }

        public void ChangeChartView(int wLevel)
        {
            _activePlot = wLevel;
        }

        public void StartGenerator()
        {
            //Thread #1 - GeneratorThread
            if (t2 == null)
            {
                t2 = new Thread(FillValuesThread);
                t2.Name = "GeneratorThread";
                //t2.IsBackground = true;
                t2.Priority = ThreadPriority.Lowest;
            }
            switch (t2.ThreadState)
            {
                case ThreadState.Unstarted:
                    t2.Start();
                    _settings.StatusString = "Преобразование запущено";
                    break;
                case ThreadState.Suspended:
                    t2.Resume();
                    _settings.StatusString = "Преобразование возобновлено";
                    break;
            }
        }

        public void StopGenerator()
        {
            if (t2 == null)
                return;
            switch (t2.ThreadState)
            {
                case ThreadState.WaitSleepJoin:
                    t2.Suspend();
                    break;
                case ThreadState.Running:
                    t2.Abort();
                    _settings.StatusString = "Преобразование остановлено";
                    break;
            }
        }

        public void FillValuesThread()
        {
            var _plotBuffer = new FixedSizedQueue<DataPoint>() { Limit = _settings.WaveletSettings.PlotBufferLength };
            var _coefBuffer = new List<DataPoint>(_settings.WaveletSettings.PlotBufferLength);
            while (true)
            {
                try
                {
                    //Запрос нового значения от генератора
                    var newValue = Generator.GenerateValue();
                    //Запись значения в буфер вейвлет обработки
                    _buffer.FitValue1D(_buffer.SignalSegment, newValue);
                    //Запись значения в буфер для графика
                    _plotBuffer.Enqueue(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), newValue));
                    _settings.Chart1Data = _plotBuffer;
                    //Применение фильтров разложения / восстановления
                    _rwp.ApplyDecFilter(_buffer, _settings.WaveletSettings.DecompilationDepth);
                    _rwp.ApplyRecFilter(_buffer, _settings.WaveletSettings.DecompilationDepth);

                    _coefBuffer = ConvertDoubleToDataPoint(_buffer.GetRow(_buffer.HfBuffer, _activePlot));
                    _settings.Chart2Data = _coefBuffer;

                    Thread.Sleep(_settings.ConnectionSettings.WagoPollCycle);
                }
                catch (Exception ex)
                {
                    t2.Abort();
                    MessageBox.Show(ex.Message);
                }
                
                //_settings.Chart2Data = ConvertDoubleToDataPoint();
                
            }
        }

        public List<DataPoint> ConvertDoubleToDataPoint(double[] dp)
        {
            var time = DateTimeAxis.ToDouble(DateTime.Now);
            var chartPoints = new List<DataPoint>();
            for (var i = 1; i < dp.Length; i++)
            {

                chartPoints.Add(new DataPoint(i /*time*/, dp[i]));
            }
            return chartPoints;

        }
    }
}